package win.smartown.android.library.faceEffects.detection;

import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.util.Log;

import com.tenginekit.face.Face;
import com.tenginekit.face.FaceDetectInfo;
import com.tenginekit.face.FaceLandmarkInfo;
import com.tenginekit.model.TenginekitPoint;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;


public class FaceDetect {


    /**
     * 接受两个参数
     *  1，图像数据 Bitmap_0，里面有人脸
     *  2，对 Bitmap_0 里面的人脸的特效操作，如 磨皮，带特效帽子等，   faceffectsE = {1，0，1，0，1} ，大眼，瘦脸，美白，特效（帽子，眉毛，下巴，耳朵等的坐标和角度）
     *  3，返回人脸关键点数据，以及特效操作后的 Bitmap_1。
     */

    private Bitmap bmp;

    //    int model; // model 为 0 为识别普通头像，1为右转头像，2为左转头像，3为眨眼
    public final static int CMD_ACTION_START=2000;// 动作,开始检测人脸
    public final static int CMD_FACE_RIGHT=2001;// 动作, 脸向右转
    public final static int CMD_FACE_LEFT=2002; // 动作, 脸向左转
    public final static int CMD_EYE_WINK=2003;// 动作,, 眨眼
    private static int actionClass; // 动作类别

    private static int model = CMD_ACTION_START; // model 为 0 为识别普通头像，1为右转头像，2为左转头像，3为眨眼
    int isRight = 1; // 成功：0，失败：1
    int pictureStata = -1; // 身份证照片的状态，模糊：-1，正常：0，脸偏右：1，脸偏左：2，眨眼：3
    int brennerMR = 300; // 清晰度阈值
    float scaleDown = 0.1f;  // 图片缩小的比例，对于身份证的ocr识别可以相对大点。

    public FaceDetect() {}


    /**
     * @方法描述 对 Bitmap 图像里面的人脸进行美白处理
     */
    public Bitmap skinWhitening(Bitmap bitmap){


        return bitmap;
    }


    /**
     * @方法描述 对 Bitmap 图像里面的人脸瘦脸处理
     */
    public Bitmap thinFace(Bitmap bitmap){


        return bitmap;
    }


    /**
     * @方法描述 对 Bitmap 图像里面的人脸局部放大处理
     * 如对眼睛进行放大处理，眼睛放大处理。接受放大的位置参数和Bitmap图像两个参数
     */
    public Bitmap localAmplification(Bitmap bitmap){


        return bitmap;
    }






    /**
     * @方法描述 Bitmap转RGB
     */
    public float getBrennerValue(Bitmap bitmap) {

        // 缩小BITMAP
        Matrix matrix = new Matrix();
        matrix.setScale(scaleDown, scaleDown);
        int bitWidth = bitmap.getWidth();
        int bitHeight = bitmap.getHeight();
        bmp = Bitmap.createBitmap(bitmap, 0, 0, bitWidth, bitHeight, matrix, true);

        //清晰度判断
        float brennerValue = 0; // 图片质量模糊度指标，会和图片大小进行正则
        double Sx = 0; // 水平方向的rgb像素值的梯度

        int bw = bmp.getWidth(), bh = bmp.getHeight();
        int intValues[] = new int[bw * bh];
        float floatValues[] = new float[bw * bh * 3];

        //  Log.e("mylog","rgbstart");
        bmp.getPixels(intValues, 0,bw, 0, 0, bw, bh);

        // BGR
        for (int i = 0; i < intValues.length; ++i) {
            int p = intValues[i];

            floatValues[i * 3 + 0] = p & 0xFF;
            floatValues[i * 3 + 1] = (p >> 8) & 0xFF;
            floatValues[i * 3 + 2] = (p >> 16) & 0xFF;

            if (i < intValues.length-2 && i > 1){
                Sx = Math.pow(floatValues[i * 3] - floatValues[(i-2) * 3], 2) ;  // x方向梯度，水平方向
            }
            brennerValue += Sx;  // 求总和
        }
        brennerValue = brennerValue / intValues.length;  // 基于图片大小进行正则

        return brennerValue;

    }


    public static FaceDetect create(int model) {

        final FaceDetect d = new FaceDetect();
        d.model = model;

        return d;
    }


    public ScanResult detect(ScanResult result) {
        Log.e("mylog", "start this line ***************************************** FaceDetect");
        //转
//        ObjLiveFace.INSTANCE.setRotation( 0, false, 1920 , 1080);
        byte[] bytesYUV = result.bytes;
        Log.e("setRotation", "bytesYUV = " + bytesYUV.length);

        // 转换数据格式，进行梯度的计算
        Bitmap bitmap = result.bitmap;

        float brennerValue = getBrennerValue(bitmap);
        Log.e("h2_000009", "brennerValue = " + brennerValue);
//
//        float brennerValue = 500.0f;
        // 基于图片brenner梯度值，进行过滤，brenner梯度值可以反应图片的清晰度
        if (brennerValue <= brennerMR) {
            //  Log.e("mylog1", "notlegi");
            // 清晰度不够退出
            result.isSucess = 1;
            result.status = pictureStata;
            Log.e("myLog", "brennerValue <= brennerMR isSuccess:" + result.isSucess + "brennerValue <= brennerMR status:" + result.status);
            return result;
        }

        Log.e("myLog", "bytesYUV.lenght = " + bytesYUV.length);
        Face.FaceDetect faceDetect = Face.detect(bytesYUV);
        int faceCount = faceDetect.getFaceCount();  // 识别出的人脸个数

        List<FaceDetectInfo> faceDetectInfos = new ArrayList<>();
        List<FaceLandmarkInfo> landmarkInfos = new ArrayList<>();
        List<TenginekitPoint> landmarksInfos = new ArrayList<>();

        if(faceCount > 0){ // 识别出了人脸

            faceDetectInfos = faceDetect.getDetectInfos();
            landmarkInfos = faceDetect.landmark2d();

        }else{
            // 没有识别出人脸
            result.isSucess = 1;
            result.status = pictureStata;
            Log.e("myLog", "no face");
            return result;
        }

        if (faceDetectInfos != null && faceDetectInfos.size() > 0) {

            // 获取人脸的眨眼，左右摇头的数据
            float facepitch = landmarkInfos.get(0).pitch;
            float faceyaw = landmarkInfos.get(0).yaw;
            float faceroll = landmarkInfos.get(0).roll;
            float faceleftEyeClose = landmarkInfos.get(0).leftEyeClose;
            float facerightEyeClose = landmarkInfos.get(0).rightEyeClose;
            landmarksInfos = landmarkInfos.get(0).landmarks;

            System.out.println("landmarksInfos:" + landmarksInfos.get(0).X + ", " + landmarksInfos.get(0).Y);
            System.out.println("landmarksInfos:" + landmarksInfos.size());
            System.out.println("landmarkInfos:" + landmarkInfos.size());

            System.out.println("**************************************************************************");
            System.out.println("facepitch:" + facepitch);
            System.out.println("faceyaw:" + faceyaw);
            System.out.println("faceroll:" + faceroll);
            System.out.println("faceleftEyeClose:" + faceleftEyeClose);
            System.out.println("facerightEyeClose:" + facerightEyeClose);

            // 获取人脸 box 的坐标点数据
            float faceboxtop = faceDetectInfos.get(0).top;
            float faceboxbottom = faceDetectInfos.get(0).bottom;
            float faceboxleft = faceDetectInfos.get(0).left;
            float faceboxright = faceDetectInfos.get(0).right;
            float faceboxheight = faceDetectInfos.get(0).height;
            float faceboxwidth = faceDetectInfos.get(0).width;


            result.boxtop = faceboxtop;
            result.boxleft = faceboxleft;
            result.boxbottom = faceboxbottom;
            result.boxright = faceboxright;
            result.faceboxheight = faceboxheight;
            result.faceboxwidth = faceboxwidth;

            System.out.println("faceboxtop=" + faceboxtop + "; faceboxbottom=" + faceboxbottom);
            System.out.println("faceboxleft=" + faceboxleft + "; faceboxright=" + faceboxright);
            System.out.println("faceboxheight=" + faceboxheight + "; faceboxwidth=" + faceboxwidth);

            // 人脸相对位置的判断,默认为 true，如果识别的人脸位置不合适，则重置为 false。
            boolean positiveFace = true;
            // 1, 人脸俯仰角度
            if(Math.abs(facepitch) > 5) positiveFace = false;
            // 2, 人脸偏航角度
            if(Math.abs(faceyaw) > 5) positiveFace = false;
            // 3, 人脸翻滚角度
            if(Math.abs(faceroll) > 5) positiveFace = false;

            // 如果是还没识别出人脸，且保证人脸是正面的
            // 则在这里生成动作检测类型
            boolean isStart = result.isStart;

            pictureStata = 0; // 表示识别出正常人脸
            }

        result.isSucess = isRight;
        result.status = pictureStata;
        result.landmarksInfos = landmarksInfos;

        Log.e("h2_00001", "isSucess = " + result.isSucess + "; status = " + result.status+ "; action = " + result.action);

        return result;
    }


    public static int randomNumb() {
        int min=2001;
        int max=2003;
        Random random = new Random();
        int s = random.nextInt(max-min+1) + min;

        return s;
    }


    public static int onCommand(int cmd){
        Log.e("h2_0001","onCommand cmd = "+ cmd);
        model = cmd;
        return cmd;
    }


}
